import jdk.internal.org.objectweb.asm.Handle;

import java.util.ArrayList;
import java.util.List;

class ListNode{
    public int val;
    public ListNode next;
    public ListNode(int val){
        this.val = val;
    }
    public ListNode(){
    }
}

public class myLink {
    public void display(ListNode head){
        ListNode cur = head;
        while (cur != null){
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }
//    2. 两数相加
//    给你两个 非空 的链表，表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的，并且每个节点只能存储 一位 数字。
//    请你将两个数相加，并以相同形式返回一个表示和的链表。
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//        表示进位数 记录十位上的数字
        int carry = 0;
//        定义一个新表
        ListNode head = new ListNode(0);
//        定义一个可移动的指针
        ListNode cur = head;
        while(l1!=null || l2!=null){
            int x = (l1 == null? 0:l1.val);
            int y = (l2 == null? 0:l2.val);
//            两个链表的值，进行相加，并加上进位数
            int sum = x + y + carry;
            carry = sum / 10;
            sum = sum % 10;
//            注意这个时候不能直接将sum赋值给cur.next = sum。这时候会报，类型不匹配。
            cur.next = new ListNode(sum);
            if(l1!=null){
                l1= l1.next;
            }
            if(l2!=null){
                l2= l2.next;
            }
            cur = cur.next;
        }
//        如果最后两个数，相加的时候有进位数的时候，就将进位数，赋予链表的新节点。
        if(carry != 0 ){
            cur.next = new ListNode(carry);
        }
        return head.next;
    }


//19. 删除链表的倒数第 N 个结点

    public ListNode removeNthFromEnd(ListNode head, int n) {
//        定义一个伪节点，用于返回结果
        ListNode pre = new ListNode(0);
        pre.next = head;
//        定义一个快指针和慢指针,指向伪节点，用于遍历链表
        ListNode slow = pre;
        ListNode fast = pre;
        while (n != 0) {
            fast = fast.next;
            n--;
        }//这个while不能放到 下面那个while里面
        while (fast.next != null) {

            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return pre.next;
    }

//      23. 合并K个升序链表
//      给你一个链表数组，每个链表都已经按升序排列。
//      请你将所有链表合并到一个升序链表中，返回合并后的链表。
//    1.时间复杂度太高有更好的方法
//    2.但等我会了再写
    public ListNode mergeKLists(ListNode[] lists) {
        ListNode head = new ListNode();//新链表头结点
        ListNode cur = head;//新链表用来移动的伪节点
        while (true){
            int minIndex = -1;//数组最小值下标

            for (int i = 0; i < lists.length; i++) {//求最小值的下标
                if (lists[i] != null){
                    if (minIndex == -1){
                        minIndex = i;
                    }
                    else {
//                        找每一个数组首值 最小的值
                        if (lists[minIndex].val > lists[i].val){
                            minIndex = i;
                        }
                    }
                }
            }

            if (minIndex == -1){
                break;
            }
            cur.next = lists[minIndex];
            cur = cur.next;
            lists[minIndex] = lists[minIndex].next;
        }
        return head.next;
    }


//      24. 两两交换链表中的节点
//      给你一个链表，两两交换其中相邻的节点，并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题（即，只能进行节点交换）。
    public ListNode swapPairs(ListNode head) {
        if (head == null){
            return null;
        }
        ListNode pre = new ListNode();
        pre.next = head;
        ListNode cur = pre;
        while (cur.next!=null && cur.next.next!=null){
            ListNode tmp = cur.next;
            ListNode tmp1 =cur.next.next.next;
            cur.next = cur.next.next;
            cur.next.next = tmp;
            tmp.next = tmp1;
            cur = cur.next.next;
        }
        return pre.next;
    }




//    25. K 个一组翻转链表
//    给你链表的头节点 head ，每 k 个节点一组进行翻转，请你返回修改后的链表
    public ListNode reverseNode(ListNode head){//反转链表
        if (head == null){
            return null;
        }
        ListNode pre = null;
        ListNode cur = head;
        ListNode tmp = null;
        while (cur != null){
            tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
            return pre;
    }
    public ListNode reverseKGroup(ListNode head, int k) {
        if (head == null){
            System.out.println("为空链表");
            return null;
        }
        ListNode dummy = new ListNode(-1);//虚拟头结点
        ListNode start = dummy;//要翻转链表的头节点
        ListNode end = dummy;//要翻转链表的尾节点
        dummy.next = head;
        while (end.next != null){
            for (int i = 0; i < k && end != null; i++) {
                end = end.next;
            }
            if (end == null){
                break;
            }
            ListNode pre = start.next;//要翻转链表的头节点的前一个节点
            ListNode last = end.next;//要翻转链表的头节点的后一个节点
            end.next = null;//要反转的那段链表尾结点置为空 再反转
            start.next = reverseNode(pre);
            pre.next = last;
            start = pre;
            end = pre;
        }
        return dummy.next;
    }




//    61. 旋转链表
//    给你一个链表的头节点 head ，旋转链表，将链表每个节点向右移动 k 个位置。
    public ListNode rotateRight(ListNode head, int k) {
        if (head==null || k<=0){
            return head;
        }
        int count = 0;//链表长度
        ListNode tail = new ListNode();//尾结点
        ListNode cur;
        for (cur=head; cur!=null; cur=cur.next){
            tail = cur;//这里tail.next=cur
            count++;
        }
        k = k%count;
        tail.next = head;
        cur = head;
        for (int i = 0; i < count-k-1; i++) {
            cur = cur.next;
        }
        head = cur.next;
        cur.next =null;
        return head;
    }



//      82. 删除排序链表中的重复元素 II
//      给定一个已排序的链表的头 head ， 删除原始链表中所有重复数字的节点，只留下不同的数字 。返回 已排序的链表
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode dummy = new ListNode(-1);
        ListNode cur = dummy;
        dummy.next = head;
        while (cur.next != null && cur.next.next != null) {//        判断cur的后两个节点是否为空
            if (cur.next.val == cur.next.next.val){ //判断cur的后两个节点的值是否相同
                int tmp = cur.next.val;//保存值
                while (cur.next != null && cur.next.val == tmp){
                    cur.next = cur.next.next;//与tmp相同则跳过该节点
                }
            }
            else {
                cur = cur.next;
            }
        }
        return dummy.next;
    }


//      83. 删除排序链表中的重复元素
//      给定一个已排序的链表的头 head ， 删除所有重复的元素，使每个元素只出现一次 。返回 已排序的链表 。
    public ListNode deleteDuplicate(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode cur = head;
        while (cur.next != null) {
            if (cur.val == cur.next.val){
                cur.next = cur.next.next;
            }
            else {
                cur = cur.next;
            }
        }
        return head;
    }



//      92. 反转链表 II
//      给你单链表的头指针 head 和两个整数 left 和 right ，其中 left <= right 。
//      请你反转从位置 left 到位置 right 的链表节点，返回 反转后的链表 。
    public  ListNode  reverseNode1(ListNode head){//重温一遍反转链表
        if (head == null){
            return null;
        }
        ListNode pre = null;
        ListNode cur = head;
        ListNode tmp = null;
        while (cur != null){
            tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
    public ListNode reverseBetween(ListNode head, int left, int right) {
//        leftNode 转换链表的头结点   pre 转换链表的头结点的前一个节点
//        rightNode 转换链表的尾结点    succ（successor前驱） 转换链表的尾结点
        if (head == null){
            return null;
        }
        int count = 0;
        ListNode dummyNode = new ListNode(-1);
        dummyNode.next = head;
        ListNode pre = head;
        while (pre != null){
            count++;//链表的长度
            pre = pre.next;
        }
//        输入是否合法
        if (left<0 || right<0 || left>right || left>count || right>count){
            System.out.println("输入不合法");
            return null;
        }

//        pre回到虚拟节点
        pre = dummyNode;
        for (int i = 0; i < left-1; i++) {
            pre = pre.next;
        }
        ListNode leftNode = pre.next;
        ListNode rightNode = pre.next;
        for (int i = 0; i < right-left; i++) {
            rightNode = rightNode.next;
        }
        ListNode succ = rightNode.next;
//        切断链接
        pre.next = null;
        rightNode.next = null;
//        接回到原来的链表中
        pre.next = reverseNode(leftNode);
        leftNode.next = succ;
        return  dummyNode.next;
    }






//    143. 重排链表
//    给定一个单链表 L 的头节点 head ，单链表 L 表示为：
//    L0 → L1 → … → Ln - 1 → Ln
//    请将其重新排列后变为：
//    L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
//    不能只是单纯的改变节点内部的值，而是需要实际的进行节点交换。
    public void reorderList(ListNode head) {
        if (head == null){
            return;
        }
//        创建个顺序表
        List<ListNode> list = new ArrayList<>();
//        将链表存到顺序表中
        while (head != null){
            list.add(head);
            head = head.next;
        }
        int left = 0;
        int right = list.size()-1;
        while (left < right){
            list.get(left).next = list.get(right);
            left++;
            if (left >= right){
                break;
            }//不放到最后 因为可以通过right 将最后一个链表数据置为空
            list.get(right).next = list.get(left);
            right--;
        }
        list.get(right).next = null;
    }



}
